package com.midipad.controls;

import android.content.Context;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import com.midipad.ConnectedThread;

/**
 * this abstract class represents a midi controller
 * all subclass implementations must extends the constructor
 * to assign a correct background and tell the correct number
 * of values they will accept (1 or 2) (for taking only the x and/or y 
 * values into account when the user touch the controller) 
 * @author Tim
 *
 */
public abstract class MidiController extends View{
	
	//pad, fader, etc
	public String name = null;
	
	//position and dimension on canvas
	public int x;
	public int y;
	public int width;
	public int height;
	//handle to the thread handling socket read/write
	protected ConnectedThread connectedThread = null;
	
	//used in the algorithm for calculating the correct midi value
	public final static int MAX_MIDI_MSG_VAL = 127; 
	
	//template of sent midi message [midi1-1, midi1-2. midiValue1, midi2-1, midi2-2, midiValue2, etc...]
	protected int[] midiMessages;
	//values touched to draw the controller
	public int [] values;
	//midi messages values to fill the template
	public int [] midiValues;
	/**
	 * 
	 * @param context the context in which to create the controller
	 * @param nbValues 1:handling only the x value when touched, 2: x and y.
	 * @param name for xml reading and writing
	 * @param x x position in px
	 * @param y y position in px
	 * @param width width in px
	 * @param height height in px
	 * @param midiMessages the midi message template : [midi1-1, midi1-2. midiValue1, midi2-1, midi2-2, midiValue2, etc...]
	 */
	public MidiController(Context context, int nbValues, String name, int x, int y, int width, int height, int[] midiMessages) {
		super(context);
		this.name=name;
		this.setLayoutParams(new ViewGroup.LayoutParams(
				ViewGroup.LayoutParams.WRAP_CONTENT,
				ViewGroup.LayoutParams.WRAP_CONTENT
		      ));
		values = new int[nbValues];// x and y
		midiValues = new int[nbValues];// x and y
		for(int i=0; i<nbValues ; i++){
			values[i]=0;
			midiValues[i]=0;
		}
		this.midiMessages = midiMessages;//this.getMidiMessages(values.length);
		this.x=x;
		this.y=y;
		this.width=width;
		this.height=height;
	}
	
	@Override 
	abstract protected void onDraw(Canvas canvas);
	
	public void setConnectedThread(ConnectedThread thread){
		this.connectedThread = thread;
	}
	
	/**
	 * if the outputstream is available on the bluetooth socket
	 * fills the template message and sends in through the socket
	 * (automatically flushed)
	 */
	public synchronized void sendMidi(){
		if(connectedThread!=null){
			//fill the template midi message
			for(int i=2, j=0 ; i<midiMessages.length ; i+=3, j++){
				midiMessages[i]=midiValues[j];
			}//write it to the socket
			connectedThread.writeInts(midiMessages);
			//Log.d("","wrote a total of "+midiMessages.length+" int to the socket");
		}
	}
	/**
	 * all sub classes must implement this!
	 * sub classes must update their midiValues member
	 * in respect to where the user touched (x and y params)
	 * @param x the x position, relative to the top left of the controller
	 * @param y the y position, relative to the top left of the controller
	 * @param me the motion event of the touch
	 */
	abstract public void updateValues(int x, int y, MotionEvent me);
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
		setMeasuredDimension(width, height);
	}
	
	public boolean concernsMe(int midi1, int midi2){
		return midi1==midiMessages[0] && midi2 == midiMessages[1];
		//TODO:override this for the second possibility when a pad
	}
	
	/**
	 * updates the values for the display, not the midi values
	 * @param val1
	 * @param val2
	 * @param val3
	 */
	abstract public void setValues(int val1, int val2, int val3);
}
